package com.example.stlink.utils;

import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import androidx.annotation.Nullable;

import com.example.stlink.configs.MySQLiteOpenHelper;

/**
 * 封装专门操作SQLite的工具类
 */
public class MySQLiteDAO {

    private static MySQLiteDAO mySQLiteDAO = null;

    private static MySQLiteOpenHelper mySQLiteOpenHelper = null;

    private MySQLiteDAO(){}

    /**
     * 懒汉式单例模式
     * 使用双重校验锁
     * 获取当前工具类的实例
     * @return 返回数据库操作类的实例
     */
    public static MySQLiteDAO newInstance(){
        if(mySQLiteDAO == null){
            synchronized (MySQLiteDAO.class){
                if(mySQLiteDAO == null){
                    mySQLiteDAO = new MySQLiteDAO();
                }
            }
        }
        return mySQLiteDAO;
    }

    /**
     * 建表
     * @param context 上下文
     * @param dbName 数据库名字
     * @param factory SQLiteDatabase.CursorFactory
     * @param version 版本
     * @param sqlCreateEntries 创建数据库的语句
     * @param sqlDeleteEntries 删除数据库的语句
     * @return 表是否创建成功
     */
    public boolean createTable(@Nullable Context context,
                                          @Nullable String dbName,
                                          @Nullable SQLiteDatabase.CursorFactory factory,
                                          int version,
                                          @Nullable String sqlCreateEntries,
                                          @Nullable String sqlDeleteEntries){
        if(mySQLiteDAO != null){
            //建表
            mySQLiteOpenHelper = new MySQLiteOpenHelper(
                    context,
                    dbName,
                    null,
                    version,
                    sqlCreateEntries,
                    sqlDeleteEntries
            );
            return true;
        }
        return false;
    }

    /**
     * 插入一条新的数据
     * @param tableName 表名
     * @param nullColumnHack 为null字段的默认值
     * @param values 需要插入的ContentValues值
     * @return 插入数据的所在的行号
     */
    public boolean insertValue(@Nullable String tableName,
                               @Nullable String nullColumnHack,
                               @Nullable ContentValues values){
        SQLiteDatabase db = mySQLiteOpenHelper.getWritableDatabase();
        db.beginTransaction();
        long rows = db.insertOrThrow(tableName, nullColumnHack, values);
        //SQLite不支持多线程同时有多个对数据库进行写操作，所以需要每次写操作结束后关闭事务和写操作
        db.setTransactionSuccessful();
        db.endTransaction();
        db.close();
        return rows != -1;
    }

    /**
     * 根据查询条件删除指定列
     * @param tableName 表名
     * @param whereClause 查询条件 使用 id=?形式，可用?占位符
     * @param whereArgs 当表达式中含有占位符，改参数用户指定各占位符参数的值
     * @return 是否删除成功
     */
    public boolean deleteValue(@Nullable String tableName,
                               @Nullable String whereClause,
                               @Nullable String[] whereArgs){
        SQLiteDatabase db = mySQLiteOpenHelper.getWritableDatabase();
        db.beginTransaction();
        long rows = db.delete(tableName,
                              whereClause,
                              whereArgs);
        db.endTransaction();
        db.close();
        return rows != -1;
    }

    /**
     * 根据查询条件更新指定列
     * @param tableName 表名
     * @param values 指定要更新的字段及对应的字段值
     * @param whereClause 查询条件 使用 id=?形式，可用?占位符
     * @param whereArgs 当表达式中含有占位符，改参数用户指定各占位符参数的值
     * @return 是否更新成功
     */
    public boolean updateValue(@Nullable String tableName,
                               @Nullable ContentValues values,
                               @Nullable String whereClause,
                               @Nullable String[] whereArgs){
        SQLiteDatabase db = mySQLiteOpenHelper.getWritableDatabase();
        db.beginTransaction();
        long rows = db.update(tableName,
                              values,
                              whereClause,
                              whereArgs);
        db.endTransaction();
        db.close();
        return rows != -1;
    }

    /**
     * 查询数据库，返回游标cursor，注意需要主程序进行关闭
     * @param tableName 表名
     * @param columns 指定要查询的列，如果为空，返回所有
     * @param selection 查询条件 使用 id=?形式，可用?占位符
     * @param selectionArgs where对应的条件值
     * @param groupBy 指定分组方式
     * @param having 指定having条件
     * @param orderBy 排序方式
     * @return 返回游标cursor
     */
    public Cursor queryValuesCursor(@Nullable String tableName,
                                              String[] columns,
                                              @Nullable String selection,
                                              @Nullable String[] selectionArgs,
                                              @Nullable String groupBy,
                                              @Nullable String having,
                                              @Nullable String orderBy){
        SQLiteDatabase db = mySQLiteOpenHelper.getWritableDatabase();
        //创建游标对象
        Cursor cursor = db.query(tableName,
                columns,
                selection,
                selectionArgs,
                groupBy,
                having,
                orderBy);
        db.close();
        return cursor;
    }

    /**
     * 查询数据库，并把所要查询的数据，装入ContentValues对象中进行返回
     * @param tableName 表名
     * @param columns 指定要查询的列，如果为空，返回所有
     * @param selection 查询条件 使用 id=?形式，可用?占位符
     * @param selectionArgs where对应的条件值
     * @param groupBy 指定分组方式
     * @param having 指定having条件
     * @param orderBy 排序方式
     * @return 查询数据装入ContentValues对象中进行返回
     */
    public ContentValues[] queryValuesContent(@Nullable String tableName,
                                       String[] columns,
                                       @Nullable String selection,
                                       @Nullable String[] selectionArgs,
                                       @Nullable String groupBy,
                                       @Nullable String having,
                                       @Nullable String orderBy){
        SQLiteDatabase db = mySQLiteOpenHelper.getWritableDatabase();
        //创建游标对象
        Cursor cursor = db.query(tableName,
                        columns,
                        selection,
                        selectionArgs,
                        groupBy,
                        having,
                        orderBy);
        ContentValues[] values = cursorHandle(cursor, columns);
        cursor.close();
        db.close();
        return values;
    }

    /**
     * 处理查询结果
     * @param cursor 查询数据库后返回的游标
     * @param columns 用户输入查询的列
     * @return 返回处理好后的结果
     */
    @SuppressLint("Range")
    private ContentValues[] cursorHandle(Cursor cursor, String[] columns){
        ContentValues[] values = new ContentValues[cursor.getCount()];
        int nowRow = 0;
        int colLen = (columns == null) ? 0 : columns.length;
        while(cursor.moveToNext()){
            if(colLen > 0){
                for (String colName : columns) {
                    int colType = cursor.getType(cursor.getColumnIndex(colName));
                    Object data = getDate(cursor, colType, colName);
                    if(data instanceof Byte[]){
                        //二进制数据，转为String类型存入
                        values[nowRow].put(colName, Byte.valueOf(String.valueOf(data)));
                    }else if(data instanceof Long){
                        values[nowRow].put(colName, (Long) data);
                    }else if (data instanceof String){
                        values[nowRow].put(colName, (String) data);
                    }else if (data instanceof Double){
                        values[nowRow].put(colName, (Double) data);
                    }else{
                        System.out.println("OtherType...............");
                    }
                }
            }
        }
        return values;
    }

    /**
     * 解析对应类的数据
     * @param cursor 游标
     * @param colType 列类型
     * @param colName 列名字
     * @return 将对应数据转化为Object超类返回
     */
    @SuppressLint("Range")
    private Object getDate(@Nullable Cursor cursor, int colType, @Nullable String colName){
        if(cursor == null){
            System.out.println("cursor = null.................");
            return null;
        }
        Object obj = null;
        switch (colType){
            case Cursor.FIELD_TYPE_NULL: {  //空类型
                break;
            }
            case Cursor.FIELD_TYPE_INTEGER: { //integer
                obj = cursor.getLong(cursor.getColumnIndex(colName));
                break;
            }
            case Cursor.FIELD_TYPE_FLOAT: { //浮动类型
                obj = cursor.getDouble(cursor.getColumnIndex(colName));
                break;
            }
            case Cursor.FIELD_TYPE_STRING: { //字符类型
                obj = cursor.getString(cursor.getColumnIndex(colName));
                break;
            }
            case Cursor.FIELD_TYPE_BLOB: {  //二进制类型
                obj = cursor.getBlob(cursor.getColumnIndex(colName));
                break;
            }
            default: {
            }
        }
        return obj;
    }
}
